package com.googlecode.todo_robot.persistence;

import com.googlecode.todo_robot.persistence.model.TodoItem;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

/**
 * @author Fuad Ibrahimov
 * @since 22.12.2009
 */
public class DbManagerImpl implements DbManager {

  @Override
  public void persist(final TodoItem todoItem) {
    doInSession(new PersistenceCallback() {
      @Override
      public Object executeWith(EntityManager em) {
        em.persist(todoItem);
        return true;
      }
    });
  }

  @Override
  public void persistTodo(String owner, String text) {
    // TODO populate todo item properly
    TodoItem todoItem = new TodoItem(owner, text.trim());
    todoItem.setPriority(TodoItem.Priority.LOW);
    todoItem.setDueDate(new Date(System.currentTimeMillis()));
    persist(todoItem);
  }

  @SuppressWarnings({"unchecked"})
  @Override
  public List<TodoItem> loadTodosOf(final String owner) {
    return (List<TodoItem>) doInSession(new PersistenceCallback() {
      @Override
      public Object executeWith(EntityManager em) {
        return em.createQuery(SELECT_NOT_SEEN_TODOS_OF).setParameter(OWNER, owner).getResultList();
      }
    });
  }

  private Object doInSession(PersistenceCallback callback) {
    EntityManager em = EMF.get().createEntityManager();
    EntityTransaction transaction = null;
    try { // TODO - cleanup transactions code
      transaction = em.getTransaction();
      transaction.begin();
      Object result = callback.executeWith(em);
      transaction.commit();
      return result;
    } catch (RuntimeException e) {
      if (transaction != null) transaction.rollback();
      throw e;
    } finally {
      em.close();
    }
  }

  private static final String SELECT_NOT_SEEN_TODOS_OF = "SELECT todo from TodoItem todo WHERE todo.owner= :owner AND todo.done = false";
  private static final String OWNER = "owner";
  private static final Logger logger = Logger.getLogger(DbManagerImpl.class.getName());


  private interface PersistenceCallback {
    Object executeWith(EntityManager em);
  }

}
